home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Hacks / Hacks ’92 / FinderMenu ƒ / FinderMenu App ƒ / localmenusharing.c < prev   
Encoding:
C/C++ Source or Header  |  1992-06-17  |  12.9 KB  |  553 lines  |  [TEXT/KAHL]

  1.  
  2. /*© Copyright 1989-1992 UserLand Software, Inc.  All Rights Reserved.*/
  3.  
  4. #include <FinderMenuInterface.h>
  5. #include <Utils.h>
  6.  
  7. #include <processes.h>
  8. #include <Menus.h>
  9. #include <GestaltEqu.h>
  10. #include <iac.h>
  11. #include <menusharing.h>
  12.  
  13. tyMSglobals MSglobals; /*Menu Sharing globals, all in one struct*/
  14.  
  15. static pascal Boolean ProcessInForeground()
  16. {
  17.     /*
  18.     return true if we're running in the foreground, false if we're in the
  19.     background.
  20.     */
  21.     
  22.     ProcessSerialNumber currentprocess, frontprocess;
  23.     Boolean fl;
  24.     
  25.     GetCurrentProcess(¤tprocess);
  26.     
  27.     GetFrontProcess(&frontprocess);
  28.     
  29.     SameProcess(¤tprocess, &frontprocess, &fl);
  30.     
  31.     return(fl);
  32. } /*ProcessInForeground*/
  33.     
  34. static Boolean FinderInForeground()
  35. {
  36.     return GetFrontProcessCreator() == 'MACS';
  37. //    'FNDR', 'MACS'
  38. }
  39.  
  40. static Boolean ServerIsRunning(void)
  41. {
  42.     return IsTargetRunning(MSglobals.serverid, nil);
  43. } /*ServerIsRunning*/
  44.  
  45.  
  46. static short CountMenuArray(void)
  47. {
  48.     /*
  49.     return the number of menus in the menu array.
  50.     */
  51.     
  52.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  53.     
  54.     if (hm == nil)
  55.         return(0);
  56.  
  57.     return((short) (GetHandleSize((Handle) hm) / sizeof(tysharedmenurecord)));
  58. } /*CountMenuArray*/
  59.  
  60.  
  61. static pascal Boolean InstallSharedMenus(short idmenuafter)
  62. {
  63.     /*
  64.     insert all of the menus in the menuarray into the menu bar.  main 
  65.     menus are inserted in front of idmenuafter. if idmenuafter is zero, 
  66.     main(non-hierarchic) menus will be added to the right of all others.
  67.     */
  68.     
  69.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  70.     reg short i, ct;
  71.     tysharedmenurecord *pItem;
  72.     
  73.     FMRollBeachball();
  74.     
  75.     ct = CountMenuArray();
  76.     
  77.     HLock(hm);
  78.     
  79.     for(i = 0; i < ct; i++) {
  80.         pItem = &(**hm) [i];
  81.  
  82.         if (pItem->flhierarchic) {
  83.             if (! FMAppend(pItem->hmenu, -1)) {
  84. #ifdef DEBUG
  85.                 DebugStr("\pfailed to insert!");
  86. #endif
  87.             }
  88.         } else {
  89.             if (! FMAppend(pItem->hmenu, idmenuafter)) {
  90. #ifdef DEBUG
  91.                 DebugStr("\pfailed to insert!");
  92. #endif
  93.             }
  94.         }
  95.         
  96.         pItem->flinserted = true; /*so we'll know it needs to be removed*/
  97.     } /*for*/
  98.     
  99.     HUnlock(hm);
  100.     
  101.     FMFreshMenuBar();
  102.  
  103.     return(true);
  104. } /*InstallSharedMenus*/
  105.  
  106.  
  107. static short GetMenuHandles(void)
  108. {
  109.     /*
  110.     loop through the menuarray, send an IAC message to the menu server requesting
  111.     that each MenuHandle be sent to us.
  112.     */
  113.  
  114.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  115.     reg short i, ct;
  116.     AppleEvent event, reply;
  117.     reg short fl;
  118.     long id;
  119.     MenuHandle hmenu;
  120.     
  121.     ct = CountMenuArray();
  122.     
  123.     for(i = 0; i < ct; i++) {
  124.         if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'gmhd', &event))
  125.             return(false);
  126.         
  127.         IACglobals.event = &event;
  128.         
  129.         if (! IACpushlongparam(MSglobals.clientid, 'menp'))
  130.             return(false);
  131.         
  132.         if (! IACpushshortparam(i, 'idix'))
  133.             return(false);
  134.  
  135.         if (! IACsendverb(IACglobals.event, &reply))
  136.             return(false);
  137.  
  138.         IACglobals.reply = &reply;
  139.  
  140.         IACglobals.event = &reply;
  141.  
  142.         fl = IACgetbinaryparam(keyDirectObject, (Handle *) &hmenu);
  143.  
  144.         IACdisposeverb(&reply);
  145.  
  146.         if (! fl)
  147.             return(false);
  148.  
  149.         (**hm)[i].hmenu = hmenu;
  150.         } /*for*/
  151.     
  152.     return(true);
  153. } /*GetMenuHandles*/
  154.  
  155.  
  156. static pascal Boolean GetSharedMenus(short firstresource)
  157. {
  158.     /*
  159.     call the menu server to get a menuarray, keyed off of our application id.
  160.     
  161.     firstresource is the starting id to be used for the menus; if there are 
  162.     n menus, their ids will range from firstresource to firstresource + n - 1.
  163.     */
  164.     
  165.     AppleEvent event, reply;
  166.     reg short fl;
  167.     OSType id;
  168.  
  169.     if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'gmry', &event))
  170.         return(false);
  171.  
  172.     IACglobals.event = &event;
  173.  
  174.     if (! IACpushlongparam(MSglobals.clientid, 'menp'))
  175.         return(false);
  176.  
  177.     if (! IACpushshortparam(firstresource, 'res1'))
  178.         return(false);
  179.  
  180.     if (! IACsendverb(&event, &reply))
  181.         return(false);
  182.  
  183.     IACglobals.event = &reply;
  184.  
  185.     fl = IACgetbinaryparam(keyDirectObject,(Handle *) &MSglobals.hsharedmenus);
  186.  
  187.     IACdisposeverb(&reply);
  188.  
  189.     if (! fl)
  190.         return(false);
  191.  
  192.     return(GetMenuHandles());
  193. } /*GetSharedMenus*/
  194.  
  195.  
  196. pascal Boolean DisposeSharedMenus(void)
  197. {
  198.     /*
  199.     completely dispose of the menuarray and the menu handles it contains.
  200.     
  201.     10/10/91 DW: check for no shared menus before disposing, save code if 
  202.     its ever called from more than one place. also set the global handle to
  203.     nil after disposing and redraw the menu bar.
  204.     */
  205.     
  206.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  207.     reg short i;
  208.     reg short ctmenus;
  209.     
  210.     if (hm == nil) /*no shared menus to toss*/
  211.         return(true);
  212.  
  213.     FMDeleteMenus();
  214.  
  215.     ctmenus = CountMenuArray();
  216.  
  217.     for(i = 0; i < ctmenus; i++) {    
  218.         DisposeMenu((**hm) [i].hmenu);
  219.     } /*for*/
  220.     
  221.     DisposHandle((Handle) hm);
  222.     
  223.     MSglobals.hsharedmenus = nil;
  224.     
  225.     FMFreshMenuBar();
  226.     
  227.     return(true);
  228. } /*DisposeSharedMenus*/
  229.  
  230. #if 0
  231.  
  232. pascal Boolean IsSharedMenu(short idmenu)
  233. {
  234.     /*
  235.     return true if the indicated menu is one of the shared menus.
  236.     */
  237.  
  238.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  239.     reg short ct, i;
  240.     tysharedmenurecord item;
  241.     
  242.     ct = CountMenuArray();
  243.     
  244.     for (i = 0; i < ct; i++) {
  245.         if ((**hm) [i].idmenu == idmenu)
  246.             return(true);
  247.     } /*for*/
  248.         
  249.     return(false);
  250. } /*IsSharedMenu*/
  251.  
  252. #else
  253.  
  254. pascal Boolean IsSharedMenu(short idmenu)
  255. {
  256.     return true;
  257. }
  258.  
  259. #endif
  260.  
  261. #if 0
  262. pascal Boolean EnableSharedMenus(Boolean flenable) {
  263.     
  264.     /*
  265.     Enables or disables the the menus in the specified menu array.
  266.     
  267.     Always returns true.
  268.     */
  269.     
  270.     reg hdlmenuarray hm = MSglobals.hsharedmenus;
  271.     reg short i;
  272.     reg short ctmenus;
  273.     reg MenuHandle hmenu;
  274.     
  275.     ctmenus = CountMenuArray();
  276.     
  277.     for(i = 0; i < ctmenus; i++) {
  278.         
  279.         hmenu =(**hm) [i].hmenu;
  280.         
  281.         if (flenable)
  282.             EnableItem(hmenu, 0);
  283.         else
  284.             DisableItem(hmenu, 0);
  285.         } /*for*/
  286.     
  287.     DrawMenuBar();
  288.     
  289.     return(true);
  290.     } /*EnableSharedMenus*/
  291. #endif
  292.  
  293. pascal Boolean RunSharedMenuItem(short idmenu, short iditem)
  294. {
  295.     /*
  296.     call the menu server to run the script linked to the indicated menu item.
  297.     the script will execute asynchonously, after this call returns.
  298.     */
  299.  
  300.     AppleEvent event, reply;
  301.     OSType id;
  302.     Boolean fl;
  303.     long refcon;
  304.     if (! IACnewverb(MSglobals.serverid, MSglobals.serverid, 'runm', &event))
  305.         return(false);
  306.     
  307.     IACglobals.event = &event;
  308.     
  309.     if (! IACpushlongparam(MSglobals.clientid, 'menp'))
  310.         return(false);
  311.     
  312.     if (! IACpushshortparam(idmenu, 'mid '))
  313.         return(false);
  314.     
  315.     if (! IACpushshortparam(iditem, 'mitm'))
  316.         return(false);
  317.     
  318.     if (! IACsendverb(&event, &reply))
  319.         return(false);
  320.  
  321.     IACglobals.event = &reply;
  322.  
  323.     fl = IACgetlongparam(keyDirectObject, &refcon);
  324.  
  325.     IACdisposeverb(&reply);
  326.  
  327.     return(fl &&(refcon != 0));
  328. } /*RunSharedMenuItem*/
  329.  
  330.  
  331. pascal Boolean CheckSharedMenus(idinsertafter) short idinsertafter;
  332. {
  333.     /*
  334.     call this from your main event loop after receiving and processing every
  335.     event. if the menus need updating, we send a message to the server asking
  336.     for our shared menus.
  337.  
  338.     if we load menus, they are assigned resource ids starting with idinsertafter.
  339.     this number must be less than 255 to allow for hierarchic menus, and must be
  340.     small enough so that no menu has an id of greater than 255. 
  341.  
  342.     9/28/91 DW: only update menus if we're the front process. this catches the
  343.     delay on re-loading a changed menu structure on the Multifinder switch. No
  344.     extra burden on the script writer editing the menu bar.
  345.     */
  346.  
  347.     if (! MSglobals.fldirtysharedmenus) /*no need for an update, return quickly*/
  348.         return(true);
  349.  
  350.     if (! FinderInForeground())
  351.         return true;
  352.  
  353. #if 0
  354.     if (! ProcessInForeground()) /*only update menus if we're the front process*/
  355.         return(true);
  356. #endif
  357.  
  358.     DisposeSharedMenus();
  359.  
  360.     if (! ServerIsRunning())
  361.         MSglobals.fldirtysharedmenus = false;
  362.     else {
  363.         if (GetSharedMenus(idinsertafter)) {
  364.             InstallSharedMenus(0); /*install to the right of all other menus*/
  365.         }
  366.         MSglobals.fldirtysharedmenus = false;
  367.     }
  368.  
  369.     return(true);
  370. } /*CheckSharedMenus*/
  371.     
  372.     
  373. pascal Boolean SharedScriptRunning()
  374. {
  375.     /*
  376.     returns true if a shared script is currently running, false otherwise.
  377.     it's provided so that an application can intelligently handle cmd-period
  378.     script termination in its keystroke handling routine.
  379.     */
  380.  
  381.     return (MSglobals.flscriptrunning);
  382. } /*SharedScriptRunning*/
  383.     
  384.     
  385. pascal Boolean CancelSharedScript()
  386. {
  387.     /*
  388.     call this when the user presses cmd-period or otherwise indicates to you that
  389.     he or she wants the currently running script to be halted. we record the fact
  390.     in the globals record. the next time we receive a message from the menu server
  391.     we'll send back an error, indicating that the script has been cancelled.
  392.     */
  393.     
  394.     if (MSglobals.flscriptrunning)
  395.         MSglobals.flscriptcancelled = true;
  396.  
  397.     return (true);
  398. } /*CancelSharedScript*/
  399.     
  400.     
  401. pascal Boolean SharedMenuHit(idmenu, iditem) short idmenu, iditem;
  402. {
  403.     /*
  404.     returns true if the indicated menu and item indicate a shared menu item.
  405.     
  406.     if not, we return false -- the item is in one of your menus, you should
  407.     process the command as you normally would.
  408.     
  409.     we send an IAC message to the menu server, requesting that the script
  410.     linked into that item be run.
  411.     
  412.     we disable the shared menus, awaiting a 'done' message to re-enable them.
  413.     */
  414.  
  415.     if (! IsSharedMenu(idmenu)) /*not a shared menu*/
  416.         return(false);
  417.  
  418. //    HiliteMenu(0);
  419.  
  420.     if (RunSharedMenuItem(idmenu, iditem)) {
  421.         MSglobals.flscriptrunning = true;
  422. //        EnableSharedMenus(false);
  423.     } else {
  424.         FMFinishedProcessing();
  425.     }
  426.             
  427.     return(true);
  428. } /*SharedMenuHit*/
  429.     
  430.  
  431. pascal Boolean SharedScriptCancelled(event, reply)
  432.     AppleEvent *event, *reply;
  433. {
  434.     
  435.     /*
  436.     call this routine in each Apple event message handler that could conceivably 
  437.     be used in a script being run by the menu server. if we return false continue
  438.     processing the message as you normally would. if we return true, that means
  439.     that the script that's running has been cancelled by the user; you should 
  440.     return noErr from your Apple event handler when we return true.
  441.     
  442.     before we return true, we reply to the message on behalf of the message
  443.     handler. we send a specific error code of 6, this should be interpreted by
  444.     the scripting system as "stop running the script, but don't display an
  445.     error dialog.
  446.     
  447.     we admit this mechanism is somewhat klunky, but it proved too difficult to have
  448.     Frontier be ready to respond to a "Cancel Script" Apple event while running
  449.     the script and also giving time slices to agents.
  450.     
  451.     10/21/91 DW: thanks to Kevin Calhoun(Apple) we can tell who sent the message.
  452.     so we only reply with an error if the message arrived from the shared menu
  453.     server. it's nice to close this loop!
  454.     */
  455.  
  456.     OSType sender;
  457.     Str255 s;
  458.     
  459.     if (MSglobals.flscriptcancelled && MSglobals.flscriptrunning) {
  460.         IACglobals.event = event;
  461.         
  462.         if (IACgetsender() == MSglobals.serverid) { /*sender is shared menu server*/
  463.             MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
  464.             s[0] = (char) 0; /*set length to 0*/
  465.             IACglobals.reply = reply;
  466.             IACreturnerror(6, s); /*server watches for this special error code*/
  467.             return(true);
  468.             }
  469.         }
  470.         
  471.     return(false); /*script not cancelled, keep processing message*/
  472. } /*SharedScriptCancelled*/
  473.  
  474.  
  475. static pascal OSErr HandleMenuDirty(event, reply, refcon)
  476.     AppleEvent *event, *reply; 
  477.     long refcon;
  478. {
  479.     /*
  480.     this Apple event handler is called when the application's menu bar has been 
  481.     edited by the script writer in the menu server's menu editor.
  482.     
  483.     we just record the dirty-ness of the menus in a boolean, we'll actually re-
  484.     load the menus when we become the foreground process.
  485.     */
  486.  
  487.     MSglobals.fldirtysharedmenus = true;
  488.     
  489.     return(noErr);
  490. } /*HandleMenuDirty*/
  491.     
  492.     
  493. static pascal OSErr HandleScriptComplete(event, reply, refcon) 
  494.     AppleEvent *event, *reply; 
  495.     long refcon;
  496. {
  497.     /*
  498.     this Apple event handler is called when a menu script has completed running.
  499.  
  500.     we update a couple of menu-sharing globals and re-enable the shared menus.
  501.  
  502.     10/8/91 DW: added callback to support Applet Manager.
  503.     */
  504.  
  505.     MSglobals.flscriptcancelled = MSglobals.flscriptrunning = false;
  506.  
  507. //    EnableSharedMenus(true);
  508.     
  509.     if (MSglobals.scriptcompletedcallback != nil)
  510.         return (*MSglobals.scriptcompletedcallback)(event, reply, refcon);
  511.     
  512.     return(noErr);
  513. } /*HandleScriptComplete*/
  514.     
  515.     
  516. pascal Boolean InitSharedMenus()
  517. {
  518.     /*
  519.     sets the program up for menu sharing. we initialize the fields of MSglobals. 
  520.     
  521.     then we get the creator id of the application we're running inside of. the menu
  522.     sharing server will need this information to be passed in an IAC message when
  523.     we're requesting our menus. 
  524.     
  525.     next, we check to see if we're running on a version of the Mac OS that supports
  526.     Apple events. if not, we return false. otherwise we install two Apple event
  527.     message handlers -- one to catch the "menu needs update" message, and another
  528.     to handle the "script has completed" message.
  529.     */
  530.     
  531.     MSglobals.serverid = 'LAND'; /*Frontier's creator id*/
  532.     MSglobals.clientid = 0;
  533.     MSglobals.hsharedmenus = nil; /*haven't loaded shared menus yet*/
  534.     MSglobals.fldirtysharedmenus = true; /*force update 1st time thru event loop*/
  535.     MSglobals.flscriptcancelled = false; /*script hasn't been cancelled*/
  536.     MSglobals.flscriptrunning = false; /*no menu script running*/
  537.     MSglobals.clientid = GetProcessCreator();
  538.     MSglobals.scriptcompletedcallback = nil;
  539.     
  540.     if (! IACinit()) /*Apple events aren't present, or otherwise couldn't init*/
  541.         return(false);
  542.     
  543.     if (! IACinstallhandler(MSglobals.clientid, 'updm',(ProcPtr) &HandleMenuDirty))
  544.         return(false);
  545.     
  546.     if (! IACinstallhandler(MSglobals.clientid, 'done',(ProcPtr) &HandleScriptComplete))
  547.         return(false);
  548.     
  549.     return(true);
  550. } /*InitSharedMenus*/
  551.  
  552.  
  553.